/*
 * copyright: Anthony Bagnall
 * 
 * */
package weka.filters.timeseries;

import java.io.FileReader;
import weka.core.Attribute;
import weka.core.DenseInstance;
import weka.core.FastVector;
import weka.core.Instance;
import weka.core.Instances;
import weka.filters.SimpleBatchFilter;

public class PowerSpectrum extends FFT {
	boolean log = false;
	FFT fftFilter;

	public void takeLogs(boolean x) {
		log = x;
	}

	public PowerSpectrum() {
		fftFilter = new FFT();
		fftFilter.useDFT();
	}

	@Override
	protected Instances determineOutputFormat(Instances inputFormat) throws Exception {
		// Set up instances size and format.
		int length = (fftFilter.findLength(inputFormat));
		length /= 2;
		FastVector atts = new FastVector();
		String name;
		for (int i = 0; i < length; i++) {
			name = "PowerSpectrum_" + i;
			atts.addElement(new Attribute(name));
		}

		if (inputFormat.classIndex() >= 0) { // Classification set, set class
			// Get the class values as a fast vector
			Attribute target = inputFormat.attribute(inputFormat.classIndex());

			FastVector vals = new FastVector(target.numValues());
			for (int i = 0; i < target.numValues(); i++)
				vals.addElement(target.value(i));
			atts.addElement(new Attribute(inputFormat.attribute(inputFormat.classIndex()).name(), vals));
		}
		Instances result = new Instances("PowerSpectrum" + inputFormat.relationName(), atts, inputFormat.numInstances());
		if (inputFormat.classIndex() >= 0)
			result.setClassIndex(result.numAttributes() - 1);

		return result;
	}

	@Override
	public Instances process(Instances instances) throws Exception {
		// Get the FFT
		// For each data, first extract the relevant data
		Instances output = determineOutputFormat(instances);
		Instances fft = fftFilter.process(instances);
		int length = fft.numAttributes();
		if (instances.classIndex() >= 0)
			length--;
		length /= 2;

		if (log) {
			double l1;
			for (int i = 0; i < fft.numInstances(); i++) {
				Instance f = fft.instance(i);
				Instance inst = new DenseInstance(length + 1);
				for (int j = 0; j < length; j++) {
					l1 = f.value(j * 2) * f.value(j * 2) + f.value(j * 2 + 1) * f.value(j * 2 + 1);
					inst.setValue(j, Math.log(l1));
				}
				// Set class value.
				// Set class value.
				if (output.classIndex() >= 0)
					inst.setValue(length, output.instance(i).classValue());
				output.add(inst);
			}

		} else {
			for (int i = 0; i < fft.numInstances(); i++) {
				Instance f = fft.instance(i);
				Instance inst = new DenseInstance(length + 1);
				for (int j = 0; j < length; j++) {
					inst.setValue(j, f.value(j * 2) * f.value(j * 2) + f.value(j * 2 + 1) * f.value(j * 2 + 1));
				}
				// Set class value.
				// Set class value.
				if (output.classIndex() >= 0)
					inst.setValue(length, fft.instance(i).classValue());
				output.add(inst);
			}
		}
		return output;
	}

	public static void waferTest() {
		/*
		 * Instances a=WekaMethods.loadData(
		 * "C:\\Research\\Data\\Time Series Data\\Time Series Classification\\wafer\\wafer_TRAIN"
		 * ); Instances b=WekaMethods.loadData(
		 * "C:\\Research\\Data\\Time Series Data\\Time Series Classification\\wafer\\wafer_TEST"
		 * ); PowerSpectrum ps=new PowerSpectrum(); try{ Instances
		 * c=ps.process(a); Instances d=ps.process(b); OutFile of = new OutFile(
		 * "C:\\Research\\Data\\Time Series Data\\Time Series Classification\\wafer\\wafer_TRAIN_PS.arff"
		 * ); OutFile of2 = new OutFile(
		 * "C:\\Research\\Data\\Time Series Data\\Time Series Classification\\wafer\\wafer_TEST_PS.arff"
		 * ); of.writeString(c.toString()); of2.writeString(d.toString());
		 * }catch(Exception e){ System.out.println(" Exception ="+e); }
		 */}

	/* Transform by the built in filter */
	public static double[] powerSpectrum(double[] d) {

		// Check power of 2
		if (((d.length) & (d.length - 1)) != 0) // Not a power of 2
			return null;
		FFT.Complex[] c = new FFT.Complex[d.length];
		for (int j = 0; j < d.length; j++) {
			c[j] = new FFT.Complex(d[j], 0.0);
		}
		FFT f = new FFT();
		f.fft(c, c.length);
		double[] ps = new double[c.length];
		for (int i = 0; i < c.length; i++)
			ps[i] = c[i].getReal() * c[i].getReal() + c[i].getImag() * c[i].getImag();
		return ps;
	}

	public static Instances loadData(String fullPath) {
		Instances d = null;
		FileReader r;
		int nosAtts;
		try {
			r = new FileReader(fullPath + ".arff");
			d = new Instances(r);
			d.setClassIndex(d.numAttributes() - 1);
		} catch (Exception e) {
			System.out.println("Unable to load data on path " + fullPath + " Exception thrown =" + e);
			e.printStackTrace();
			System.exit(0);
		}
		return d;
	}

	public static void matlabComparison() {

		// MATLAB Output generated by
		// Power of 2: use FFT
		// Create set of instances with 16 attributes, with values
		// Case 1: All Zeros
		// Case 2: 1,2,...16
		// Case 3: -8,-7, -6,...,0,1,...7
		// Case 4: 0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1
		/*
		 * PowerSpectrum ps=new PowerSpectrum();
		 * 
		 * Instances test1=ClassifierTools.loadData(
		 * "C:\\Users\\ajb\\Dropbox\\TSC Problems\\TestData\\FFT_test1");
		 * Instances test2=ClassifierTools.loadData(
		 * "C:\\Users\\ajb\\Dropbox\\TSC Problems\\TestData\\FFT_test2");
		 * Instances t2; try{ t2=ps.process(test1);
		 * System.out.println(" TEST 1 PS ="+t2); t2=ps.process(test2);
		 * System.out.println(" TEST 2 PS ="+t2);
		 * 
		 * 
		 * }catch(Exception e){ System.out.println(" Errrrrrr = "+e);
		 * e.printStackTrace(); System.exit(0); }
		 */
		// Not a power of 2: use padding

		// Not a power of 2: use truncate

		// Not a power of 2: use DFT

	}

	public static void main(String[] args) {
		matlabComparison();
		System.exit(0);
		PowerSpectrum ps = new PowerSpectrum();
		System.out.println(" " + ps.getInputFormat());
		Instances in = loadData("C:\\Research\\Data\\Time Series Classification\\Beef\\Beef_Train");

		try {
			Instances out = ps.process(in);
			System.out.println(" " + out.numAttributes() + " " + out.numInstances());
			Instance ins = out.instance(0);
			double[] vals = ins.toDoubleArray();
			System.out.println(" Class index =" + out.classIndex());
			System.out.println(" Num atts =" + out.numAttributes());

			System.out.println(" " + ins.value(out.classIndex()));
			// for(double d:vals)
			// System.out.println(" PS  "+d);
		} catch (Exception e) {
			System.out.println(" Error =" + e);
			e.printStackTrace();
		}

	}

}
